import json
import os
import re
from typing import Dict, Any, Union, List

from requests import Response

from Logs.log_handle import get_log
from tools.allure_step import allure_step
from tools.request_utils.after_handle_utils import response_type, json_extractor, re_extract

log = get_log(os.path.split(__file__)[-1])


def assert_value(actual: str, expected: str, assert_type: str) -> None:
    """
    根据断言类型进行断言
    :param assert_type: 断言类型，可选值包括：
        - 'eq': 相等，例如 {'eq': {'$.code': '203'}
        - 'in': 包含关系，例如 {'in': {'$.message': 'success'}}
        - 'gt': 大于，例如 {'gt': {'$.amount': '100'}}
        - 'lt': 小于，例如 {'lt': {'$.amount': '100'}}
        - 'not': 不等于，例如 {'not': {'$.status': '404'}}
        - 'ge': 大于等于，例如 {'ge': {'$.rating': '4.5'}}
        - 'le': 小于等于，例如 {'le': {'$.rating': '4.5'}}
        - 'starts_with': 以某个字符串开头，例如 {'starts_with': {'$.url': 'http://'}}
        - 'ends_with': 以某个字符串结尾，例如 {'ends_with': {'$.filename': '.txt'}}
        - 'regex': 正则表达式匹配，例如 {'regex': {'$.email': r'^[\w\.-]+@[\w\.-]+'}}
    使用：{'eq': {'$.code': '203','$.code': '200'},'in': {'$.message': 'success'}}
    """

    if assert_type == "eq":  # 相等
        assert actual == expected
    elif assert_type == "in":  # 包含关系
        assert expected in actual
    elif assert_type == "gt":  # 大于
        assert float(actual) > float(expected)
    elif assert_type == "lt":  # 小于
        assert float(actual) < float(expected)
    elif assert_type == "not":  # 不等于
        assert actual != expected
    elif assert_type == "ge":  # 大于等于
        assert float(actual) >= float(expected)
    elif assert_type == "le":  # 小于等于
        assert float(actual) <= float(expected)
    elif assert_type == "starts_with":  # 以某个字符串开头
        assert actual.startswith(expected)
    elif assert_type == "ends_with":  # 以某个字符串结尾
        assert actual.endswith(expected)
    elif assert_type == "regex":  # 正则表达式匹配
        assert re.search(expected, actual) is not None
    else:
        raise ValueError(f"无效的断言类型: {assert_type}")


def extract_actual_value(response: Response, key: str) -> Any:
    """根据响应类型提取实际值"""
    if key == "http_code":
        return response.status_code
    if response_type(response) == "json":
        return json_extractor(response.json(), key)
    return re_extract(response.text, key)


# 断言处理
def assert_result(response: Response, expected: Union[Dict[str, Dict[str, Any]], str]) -> tuple[List[str], List[str]]:
    """断言方法，返回 (actual_list, error_list) 两个列表"""
    if not expected:
        log.info("当前用例无断言！")
        return [], []

    # 如果 expected 是字符串类型，尝试将其解析为字典
    if isinstance(expected, str):
        try:
            expected = json.loads(expected)  # 尝试解析为字典
        except json.JSONDecodeError:
            log.error(f"解析断言字符串失败: {expected}")
            return [], []

    actual_list = []
    error_list = []

    log.info("开始进行断言校验...")

    for assert_type, assertions in expected.items():
        for key, expected_value in assertions.items():
            log.info(f"开始处理断言：{assert_type} - {key} | 预期值：{expected_value}")
            actual = extract_actual_value(response, key)
            actual_str = str(actual)
            expected_str = str(expected_value)

            log_entry = f'{key}: 实际结果:{actual_str} | 预期结果:{expected_str} 断言方式：{assert_type}'
            log.info(log_entry)

            # 判断断言是否成功
            if actual_str == expected_str:
                actual_list.append(log_entry)  # 记录成功的断言
            else:
                error_list.append(log_entry)  # 记录失败的断言

    # 记录成功的断言数据
    if actual_list:
        allure_step('成功的断言数据', actual_list)
        log.info(f"有 {len(actual_list)} 个断言成功。")

    # 记录失败的断言数据
    if error_list:
        allure_step('失败的断言数据', error_list)
        log.error(f"有 {len(error_list)} 个断言失败。请查看 Allure 报告中的失败部分。")

    log.info("断言校验完成。")

    return actual_list, error_list
